package com.katesoft.scale4j.persistent.client;

import com.katesoft.scale4j.persistent.model.unified.AbstractPersistentEntity;
import com.katesoft.scale4j.persistent.types.RevisionData;
import org.springframework.dao.DataAccessException;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Convenient super class for Hibernate-based data access objects.
 * <p/>
 * This base class is mainly intended for LocalHibernateTemplate usage.
 * <p/>
 * You can find method to work with historical data here and convenient method to perform lucene search operations on top of domain classes.
 *
 * @author kate2007
 */
public interface IHibernateDaoSupport
{
    /**
     * Searches for persistent entities of the given entityClass based on query string. <p> Note: This method must be used only if entity class is annotated
     * with @Indexed annotation. <p/> Also this method can't cause {@link OutOfMemoryError} because restricts max result to pre-defined maximum size. <p/>
     * Search is restricted by given properties. </p>
     *
     * @param <T>         type of entity.
     * @param queryString search string or <code>NULL</code>.
     * @param entityClass entity class.
     * @param properties  search restriction fields.
     * @return list of founded entities.
     * @throws org.springframework.dao.DataAccessException
     *          any jdbc exception.
     * @see org.apache.lucene.search.Query
     */
    <T extends AbstractPersistentEntity> List<T> search(final String queryString,
                                                        final Class<T> entityClass,
                                                        final String[] properties) throws DataAccessException;

    /**
     * looking for latest revision of entity. latest revision always exists unless there is no such entity(with given unique identifier).
     *
     * @param entityClass      domain class
     * @param uniqueIdentifier domain entity unique identifier
     * @param <T>              type of entity
     * @return latest revision of entity.
     * @throws org.springframework.dao.DataAccessException
     *          any jdbc exception.
     */
    <T extends AbstractPersistentEntity> Number latestRevision(Class<T> entityClass,
                                                               long uniqueIdentifier) throws DataAccessException;

    /**
     * looking up for the all revisions of entity(result list is sorted by revision number in descending order).
     *
     * @param entityClass      domain class
     * @param uniqueIdentifier domain entity unique identifier
     * @param <T>              type of entity
     * @return sorted collection of all revisions of entity.
     * @throws org.springframework.dao.DataAccessException
     *          any jdbc exception.
     */
    <T extends AbstractPersistentEntity> List<Number> allRevisions(Class<T> entityClass,
                                                                   long uniqueIdentifier) throws DataAccessException;

    /**
     * retrieve revision data information of entity(all versions ordered by revision number desc).
     *
     * @param entityClass      domain class
     * @param uniqueIdentifier domain entity unique identifier
     * @param <T>              type of entity
     * @return sorted collection of all revision data information of entity.
     * @throws org.springframework.dao.DataAccessException
     *          any jdbc exception.
     */
    <T extends AbstractPersistentEntity> List<RevisionData<T>> loadAllRevisions(Class<T> entityClass,
                                                                                long uniqueIdentifier) throws DataAccessException;

    /**
     * looking entity's revision historical data by given date(maximum date less or equals given) - the most up to date revision will be picked.
     * <p/>
     * This method allows you to pass multiple primary keys and result will be map where keys are unique identifiers.
     * <p/>
     * May be useful - result map is actually LinkedHashMap(so ordered according to unique identifiers collection).
     * <p/>
     * Also please note that in case when no revision data found for particular identified, nothing will be added to result map.
     *
     * @param entityClass       domain class
     * @param date              historical data date
     * @param uniqueIdentifiers collection of unique identifiers
     * @param property          date property to be used(if not specified revision timestamp will be used)
     * @param <T>               type of entity
     * @return map where key is unique identifier and value is revision data
     * @throws org.springframework.dao.DataAccessException
     *          any jdbc exception.
     */
    <T extends AbstractPersistentEntity> Map<Long, RevisionData<T>> latestRevisionForDate(Class<T> entityClass,
                                                                                          Date date,
                                                                                          Collection<Long> uniqueIdentifiers,
                                                                                          String property) throws DataAccessException;

    /**
     * looking entity's revision historical data by given date(maximum date less or equals given) - the most up to date revision will be picked.
     *
     * @param entityClass      domain class
     * @param date             historical data date
     * @param uniqueIdentifier primary key of entity
     * @param property         date property to be used(if not specified revision timestamp will be used)
     * @param <T>              type of entity
     * @return revision data for unique identifier or <code>NULL</code> if nothing found.
     * @throws org.springframework.dao.DataAccessException
     *          any jdbc exception.
     */
    <T extends AbstractPersistentEntity> RevisionData<T> latestRevisionForDate(Class<T> entityClass,
                                                                               Date date,
                                                                               long uniqueIdentifier,
                                                                               String property) throws DataAccessException;
    IHibernateOperations getLocalHibernateTemplate();
}
